package com.finalproject.entity;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;



/**
 * 
 * @author Cagri Akargun
 * @author Ballori Sengupta
 */

public class ExpenseProfile  {
	private double fundsUsed = 0;			// running total of funds being used. 
	private double fundsAvailable = 0;		// remaining funds available 
	private LinkedList<ExpenseEntry> expenseHistory= new LinkedList<ExpenseEntry>();


	public interface ExpenseProfileObserver {
		public void onUpdate(ExpenseProfile expenseProfile);
	}
	
	
	
	private List<ExpenseProfileObserver> experenseProfileObservers;
	
	
	public ExpenseProfile() {
		this.experenseProfileObservers = new ArrayList<ExpenseProfileObserver>();
	}
	
	
	
	
	
	/**
	 * Removes the given amount of funds from available funds and adds that amount to used funds
	 * adds the expense entry with the current day and amount to the expense history
	 * @param amount Amount to be subtracted from the available funds/added to the used funds
	 * @throws InsufficientFundsException 
	 * @throws IllegalArgumentException
	 * */
	public void removeFunds(double amount) throws InsufficientFundsException
	{	
		if (amount<0)
			throw new IllegalArgumentException("the amount entered is a negative number");
		if ((getFundsAvailable() - amount)<0)
			throw new InsufficientFundsException("insufficient funds!");
		
		Calendar today=Calendar.getInstance();
		ExpenseEntry tempEntry;
		setFundsUsed(getFundsUsed() + amount);
		setFundsAvailable(getFundsAvailable() - amount);
		
		if (!expenseHistory.isEmpty()){
			tempEntry=expenseHistory.removeLast();
			Calendar tempDay=tempEntry.getDate();
			if ((today.get(Calendar.DAY_OF_MONTH)==tempDay.get(Calendar.DAY_OF_MONTH)) && (today.get(Calendar.MONTH)==tempDay.get(Calendar.MONTH)) && (today.get(Calendar.YEAR)==tempDay.get(Calendar.YEAR))){
				amount+=tempEntry.getAmount();
				expenseHistory.addLast(new ExpenseEntry(today,amount,getFundsAvailable()));
			}
			else{
				expenseHistory.addLast(tempEntry);
				amount+=tempEntry.getAmount();
				expenseHistory.addLast(new ExpenseEntry(today,amount,getFundsAvailable()));
			}
		}
		else{
			expenseHistory.addLast(new ExpenseEntry(today,amount,getFundsAvailable()));
		}
		fireExpenseProfileObserver(this);
	}
	/**
	 * Removes the given amount of funds from available funds and adds that amount to used funds
	 * adds the expense entry with the given date and amount to the expense history
	 * @param amount Amount to be subtracted from the available funds/added to the used funds
	 * @param date The date of the expense entry
	 * @throws InsufficientFundsException  
	 * @throws IllegalArgumentException
	 * */
	public void removeFunds(double amount, Calendar date) throws InsufficientFundsException{
		if (amount<0)
			throw new IllegalArgumentException("the amount entered is a negative number");
		if ((getFundsAvailable() - amount)<0)
			throw new InsufficientFundsException("insufficient funds!");
		
		ExpenseEntry tempEntry;
		setFundsUsed(getFundsUsed() + amount);
		setFundsAvailable(getFundsAvailable() - amount);
		
		if (!expenseHistory.isEmpty()){
			/*
			ExpenseEntry newOne=new ExpenseEntry(date, amount);
			
			for(int i=0;i<expenseHistory.size();i++){
				tempEntry=expenseHistory.get(i);
				if (tempEntry.sameDate(newOne)){
					amount+=tempEntry.getAmount();
					expenseHistory.remove(i);
					expenseHistory.add(i,new ExpenseEntry(date, amount));
					break;
				}
				else
					expenseHistory.addFirst(newOne);	
			}*/
		
			tempEntry=expenseHistory.removeLast();
			
			Calendar tempDay=tempEntry.getDate();
			if ((date.get(Calendar.DAY_OF_MONTH)==tempDay.get(Calendar.DAY_OF_MONTH)) && (date.get(Calendar.MONTH)==tempDay.get(Calendar.MONTH)) && (date.get(Calendar.YEAR)==tempDay.get(Calendar.YEAR))){
				amount+=tempEntry.getAmount();
				expenseHistory.addLast(new ExpenseEntry(date,amount,getFundsAvailable()));
			}
			else{
				expenseHistory.addLast(tempEntry);
				expenseHistory.addLast(new ExpenseEntry(date,amount+tempEntry.getAmount(),getFundsAvailable()));
			}
			
		}
		else{
			expenseHistory.addLast(new ExpenseEntry(date,amount,getFundsAvailable()));
		}
		
		System.out.println("ExpenseHistory:" + expenseHistory);
		fireExpenseProfileObserver(this);
		
		
	}
	/**
	 * Adds the given amount of funds to available funds 
	 * @param amount Amount to be added to available funds
	 * @throws InsufficientFundsException 
	 * @throws IllegalArgumentException
	 * */
	public void addFunds(double amount){
		if (amount<0)
			throw new IllegalArgumentException("the amount entered is a negative number");
		setFundsAvailable(getFundsAvailable() + amount);
		fireExpenseProfileObserver(this);
	}
	public double getFundsAvailable() {
		return fundsAvailable;
	}

	public void setFundsAvailable(double fundsAvailable) {
		this.fundsAvailable = fundsAvailable;
	}

	public double getFundsUsed() {
		return fundsUsed;
	}

	public void setFundsUsed(double fundsUsed) {
		this.fundsUsed = fundsUsed;
	}

	
	
	
	public void addExpenseProfileObserver(ExpenseProfileObserver expenseProfileObserver) {
		experenseProfileObservers.add(expenseProfileObserver);
	}
	
	
	public void removeExpenseProfileObserver(ExpenseProfileObserver expenseProfileObserver) {
		experenseProfileObservers.remove(expenseProfileObserver);
	}
	
	
	
	private void fireExpenseProfileObserver(ExpenseProfile expenseProfile) {
		for(ExpenseProfileObserver expenseProfileObserver: experenseProfileObservers) {
			expenseProfileObserver.onUpdate(this);
		}
	}
	
	

	public List<ExpenseEntry> getExpenseEntries() {
		
//		Collections.sort(expenseHistory,new Comparator<ExpenseEntry>() {
//
//			@Override
//			public int compare(ExpenseEntry o1, ExpenseEntry o2) {
//				Calendar date = o1.getDate();
//				Calendar date2 = o2.getDate();
//				return date.compareTo(date2);
//			}
//		});
		return expenseHistory;
	}



}
